﻿using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using revDb = Autodesk.Revit.DB;
using System.Threading;
using Newtonsoft.Json;
using RevitAddin1;
using xxyyzz = RevitAddin.XYZ;
using ParamSettings;




namespace RevitTest
{
    [TransactionAttribute(TransactionMode.Manual)]
    [RegenerationAttribute(RegenerationOption.Manual)]
    public class Lofting : IExternalEventHandler
    {
        public List<List<XYZ>> results { get; set; }

        public void Execute(UIApplication app)
        {
            UIDocument uiDoc = app.ActiveUIDocument;
            Document doc = uiDoc.Document;
            this.results = new List<List<XYZ>>();

            #region 读取点坐标

            NewExecute();

            #endregion

            if (this.results != null)
            {
                int i = 0;
                foreach (var restult in this.results)
                {
                    List<revDb.XYZ> temp = new List<revDb.XYZ>();
                    foreach (var item in restult) temp.Add(new revDb.XYZ(item.X, item.Y, item.Z));
                    temp = exDistinctElement(temp);
                    string familyPath =
                        @"C:\\ProgramData\\Autodesk\\RVT 2020\\Family Templates\\Chinese\\自适应公制常规模型.rft";
                    Document familyDoc = doc.Application.NewFamilyDocument(familyPath);

                    bool isFail = false;
                    Transaction ts = new Transaction(familyDoc, Guid.NewGuid().ToString());
                    BeeFaceFailureHandler.SetFailedHandlerBeforeTransaction(new BeeFaceFailureHandler(), ts);
                    ts.Start();
                    try
                    {
                        this.runSwept(familyDoc, temp);
                    }
                    catch (Exception ex)
                    {
                        isFail = true;
                    }

                    ts.Commit();

                    //if(isFail) continue;


                    string filePathDirectory = ParamManager.getParamValue(RevitAddin.globalVar.pathParam, "放样族文件输出路径", "D:\\FamilyTemp\\");
                    string path = $"{filePathDirectory}{i}.rfa";
                    SaveAsOptions saveAsOption = new SaveAsOptions();
                    saveAsOption.OverwriteExistingFile = true;
                    try
                    {
                        familyDoc.SaveAs(path, saveAsOption);
                        Thread.Sleep(1000);

                        familyDoc.Close();
                        Family family;
                        Transaction tc = new Transaction(doc, Guid.NewGuid().ToString().Substring(0, 10));
                        BeeFaceFailureHandler.SetFailedHandlerBeforeTransaction(new BeeFaceFailureHandler(), tc);
                        tc.Start();
                        doc.LoadFamily(path, new FamilyLoadOptionsDefault(), out family);
                        tc.Commit();

                        Transaction tcc = new Transaction(doc, Guid.NewGuid().ToString().Substring(0, 10));
                        BeeFaceFailureHandler.SetFailedHandlerBeforeTransaction(new BeeFaceFailureHandler(), tcc);
                        tcc.Start();
                        ElementId eid = family.GetFamilySymbolIds().FirstOrDefault();
                        FamilySymbol fs = doc.GetElement(eid) as FamilySymbol;
                        fs.Activate();
                        FamilyInstance instance =
                            doc.Create.NewFamilyInstance(revDb.XYZ.Zero, fs, StructuralType.NonStructural);
                        tcc.Commit();
                    }
                    catch (Exception ex)
                    {
                        int c = 0;
                        c++;
                    }

                    i++;
                    //break;
                }
            }
        }

        public string GetName()
        {
            return "123";
        }

        public void NewExecute()
        {
            // 文件路径
            //string filePath = @"D:\resultPointListDicOutput.txt";
            string filePath = ParamManager.getParamValue(RevitAddin.globalVar.pathParam, RevitAddin.globalVar.wiringResultPath, "D:\\resultPointListDicOutput.txt");
            if (!File.Exists(filePath))
            {
                TaskDialog.Show("错误", $"文件不存在：{filePath}");
                return;
            }

            // 读取文件内容并反序列化
            string fileContent = File.ReadAllText(filePath);
            Dictionary<string, Dictionary<string, List<xxyyzz>>> coordinatesDict;

            try
            {
                coordinatesDict =
                    JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, List<xxyyzz>>>>(fileContent);
            }
            catch (Exception ex)
            {
                TaskDialog.Show("错误", $"反序列化失败：{ex.Message}");
                return;
            }


            // 遍历 coordinatesDict 以确保所有点间距满足要求
            foreach (var outerPair in coordinatesDict.Keys.ToList()) // 使用 ToList() 创建副本，以便修改原始字典
            {
                var innerDict = coordinatesDict[outerPair];

                foreach (var innerKey in innerDict.Keys.ToList()) // 遍历内层字典的 Keys，并使用 ToList()
                {
                    List<xxyyzz> filteredPoints = new List<xxyyzz>();
                    List<xxyyzz> points = innerDict[innerKey];

                    // 添加第一个点
                    if (points.Count > 0)
                    {
                        filteredPoints.Add(points[0]);
                    }

                    // 过滤相邻点距离小于容差的点
                    for (int i = 1; i < points.Count; i++)
                    {
                        xxyyzz lastPoint = filteredPoints[filteredPoints.Count - 1];
                        xxyyzz currentPoint = points[i];


                        filteredPoints.Add(currentPoint);
                    }

                    // 将过滤后的点列表替换为原始字典中的值
                    innerDict[innerKey] = filteredPoints;
                    List<XYZ> resultPoints = new List<XYZ>();
                    foreach (var VARIABLE in filteredPoints)
                    {
                        var NewPoint = new XYZ(VARIABLE.X, VARIABLE.Y, VARIABLE.Z);
                        resultPoints.Add(NewPoint);
                    }

                    results.Add(resultPoints);
                }
            }
        }

        private void runSwept(Document familyDoc, List<revDb.XYZ> Points)
        {
            double space = 0.1;
            for (double param = 0; param < 1; param += space)
            {
                ReferencePointArray refPointArray = new ReferencePointArray();
                Points.ForEach(item =>
                {
                    ReferencePoint referencePoint = familyDoc.FamilyCreate.NewReferencePoint(item);
                    refPointArray.Append(referencePoint);
                });

                CurveByPoints curveByPoints = familyDoc.FamilyCreate.NewCurveByPoints(refPointArray);
                Transform transStart = curveByPoints.GeometryCurve.ComputeDerivatives(param, true);
                Transform transEnd = curveByPoints.GeometryCurve.ComputeDerivatives(param + space, true);

                double lengthInch = curveByPoints.GeometryCurve.Length;
                double lengthMm = lengthInch * 304.8;

                //起始轮廓
                Plane plane = Plane.CreateByNormalAndOrigin(transStart.BasisX, transStart.Origin);
                SketchPlane sketchPlane = SketchPlane.Create(familyDoc, plane);
                Arc arc = Arc.Create(plane, (60 / 2) / 304.7999995367, 0, Math.PI * 2);
                //Arc arc = Arc.Create(plane, 10 / 304.7999995367, 0, Math.PI * 2);
                ModelCurve modelArcStart = familyDoc.FamilyCreate.NewModelCurve(arc, sketchPlane);

                //结束轮廓
                plane = Plane.CreateByNormalAndOrigin(transEnd.BasisX, transEnd.Origin);
                sketchPlane = SketchPlane.Create(familyDoc, plane);
                arc = Arc.Create(plane, (60 / 2) / 304.7999995367, 0, Math.PI * 2);
                //Arc arc = Arc.Create(plane, 10 / 304.7999995367, 0, Math.PI * 2);
                ModelCurve modelArcEnd = familyDoc.FamilyCreate.NewModelCurve(arc, sketchPlane);

                ReferenceArray guideLine = new ReferenceArray();
                guideLine.Append(curveByPoints.GeometryCurve.Reference);

                ReferenceArrayArray referAll = new ReferenceArrayArray();
                ReferenceArray refersa = new ReferenceArray();
                refersa.Append(modelArcStart.GeometryCurve.Reference);
                ReferenceArray refersa1 = new ReferenceArray();
                refersa1.Append(modelArcEnd.GeometryCurve.Reference);
                referAll.Append(refersa);
                referAll.Append(refersa1);

                try
                {
                    familyDoc.FamilyCreate.NewSweptBlendForm(true, guideLine, referAll);
                }
                catch (Exception ex)
                {
                    double nextSpace = space / 10;
                    for (int j = 0; j < 10; j++)
                    {
                        double startParam = param + nextSpace * j;
                        double endParam = startParam + nextSpace;

                        refPointArray = new ReferencePointArray();
                        Points.ForEach(item =>
                        {
                            ReferencePoint referencePoint = familyDoc.FamilyCreate.NewReferencePoint(item);
                            refPointArray.Append(referencePoint);
                        });

                        curveByPoints = familyDoc.FamilyCreate.NewCurveByPoints(refPointArray);
                        transStart = curveByPoints.GeometryCurve.ComputeDerivatives(startParam, true);
                        transEnd = curveByPoints.GeometryCurve.ComputeDerivatives(endParam, true);


                        //起始轮廓
                        plane = Plane.CreateByNormalAndOrigin(transStart.BasisX, transStart.Origin);
                        sketchPlane = SketchPlane.Create(familyDoc, plane);
                        arc = Arc.Create(plane, (60 / 2) / 304.7999995367, 0, Math.PI * 2);
                        //Arc arc = Arc.Create(plane, 10 / 304.7999995367, 0, Math.PI * 2);
                        modelArcStart = familyDoc.FamilyCreate.NewModelCurve(arc, sketchPlane);

                        //结束轮廓
                        plane = Plane.CreateByNormalAndOrigin(transEnd.BasisX, transEnd.Origin);
                        sketchPlane = SketchPlane.Create(familyDoc, plane);
                        arc = Arc.Create(plane, (60 / 2) / 304.7999995367, 0, Math.PI * 2);
                        //Arc arc = Arc.Create(plane, 10 / 304.7999995367, 0, Math.PI * 2);
                        modelArcEnd = familyDoc.FamilyCreate.NewModelCurve(arc, sketchPlane);

                        guideLine = new ReferenceArray();
                        guideLine.Append(curveByPoints.GeometryCurve.Reference);

                        referAll = new ReferenceArrayArray();
                        refersa = new ReferenceArray();
                        refersa.Append(modelArcStart.GeometryCurve.Reference);
                        refersa1 = new ReferenceArray();
                        refersa1.Append(modelArcEnd.GeometryCurve.Reference);
                        referAll.Append(refersa);
                        referAll.Append(refersa1);


                        try
                        {
                            familyDoc.FamilyCreate.NewSweptBlendForm(true, guideLine, referAll);
                        }
                        catch (Exception exNext)
                        {
                            //nextSpace = nextSpace / 10;
                            double current = startParam;
                            while (current <= endParam)
                            {
                                //double startParamNext = startParam + nextSpace * k;
                                //endParam = startParamNext + nextSpace;

                                double startParamNext = current;
                                double endParamNext = startParamNext + 50 / lengthMm;

                                transStart = curveByPoints.GeometryCurve.ComputeDerivatives(startParamNext, true);
                                transEnd = curveByPoints.GeometryCurve.ComputeDerivatives(endParamNext, true);

                                //起始轮廓
                                plane = Plane.CreateByNormalAndOrigin(transStart.BasisX, transStart.Origin);
                                sketchPlane = SketchPlane.Create(familyDoc, plane);
                                arc = Arc.Create(plane, (60 / 2) / 304.7999995367, 0, Math.PI * 2);
                                //Arc arc = Arc.Create(plane, 10 / 304.7999995367, 0, Math.PI * 2);
                                modelArcStart = familyDoc.FamilyCreate.NewModelCurve(arc, sketchPlane);

                                //结束轮廓
                                plane = Plane.CreateByNormalAndOrigin(transEnd.BasisX, transEnd.Origin);
                                sketchPlane = SketchPlane.Create(familyDoc, plane);
                                arc = Arc.Create(plane, (60 / 2) / 304.7999995367, 0, Math.PI * 2);
                                //Arc arc = Arc.Create(plane, 10 / 304.7999995367, 0, Math.PI * 2);
                                modelArcEnd = familyDoc.FamilyCreate.NewModelCurve(arc, sketchPlane);

                                referAll = new ReferenceArrayArray();
                                refersa = new ReferenceArray();
                                refersa.Append(modelArcStart.GeometryCurve.Reference);
                                refersa1 = new ReferenceArray();
                                refersa1.Append(modelArcEnd.GeometryCurve.Reference);
                                referAll.Append(refersa);
                                referAll.Append(refersa1);


                                try
                                {
                                    familyDoc.FamilyCreate.NewLoftForm(true, referAll);
                                }
                                catch (Exception exNext1)
                                {
                                    transStart = curveByPoints.GeometryCurve.ComputeDerivatives(startParamNext, true);
                                    transEnd = curveByPoints.GeometryCurve.ComputeDerivatives(endParamNext, true);

                                    //起始轮廓
                                    plane = Plane.CreateByNormalAndOrigin(transStart.BasisX, transStart.Origin);
                                    sketchPlane = SketchPlane.Create(familyDoc, plane);
                                    arc = Arc.Create(plane, (60 / 2) / 304.7999995367, 0, Math.PI * 2);
                                    //Arc arc = Arc.Create(plane, 10 / 304.7999995367, 0, Math.PI * 2);
                                    modelArcStart = familyDoc.FamilyCreate.NewModelCurve(arc, sketchPlane);

                                    //结束轮廓
                                    plane = Plane.CreateByNormalAndOrigin(transEnd.BasisX, transEnd.Origin);
                                    sketchPlane = SketchPlane.Create(familyDoc, plane);
                                    arc = Arc.Create(plane, (60 / 2) / 304.7999995367, 0, Math.PI * 2);
                                    //Arc arc = Arc.Create(plane, 10 / 304.7999995367, 0, Math.PI * 2);
                                    modelArcEnd = familyDoc.FamilyCreate.NewModelCurve(arc, sketchPlane);
                                }

                                current = endParamNext;

                            }
                        }

                    }
                }

            }
        }


        public static List<XYZ> exDistinctElement(List<XYZ> xyzs)
        {
            List<XYZ> result = new List<XYZ>();
            foreach (XYZ xyz in xyzs)
            {
                bool isExist = false;
                foreach (XYZ z in result)
                {
                    if (z.IsAlmostEqualTo(xyz))
                    {
                        isExist = true;
                        break;
                    }
                }
                if (!isExist)
                {
                    result.Add(new XYZ(xyz.X, xyz.Y, xyz.Z));
                }
            }

            return result;
        }

    }




    public class FamilyLoadOptionsDefault : IFamilyLoadOptions
    {
        public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues)
        {
            //重写内容
            overwriteParameterValues = true;
            return true;
        }

        public bool OnSharedFamilyFound(Family sharedFamily, bool familyInUse, out FamilySource source, out bool overwriteParameterValues)
        {
            source = FamilySource.Project;
            overwriteParameterValues = true;
            return true;
        }
    }
}